package com.ffpc.sql;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;

/**
 * <p>Connection provider adapter for JNDI data sources.</p>
 * 
 * <p>Supported configuration keys (prefix omitted for clarity):</p>
 * 
 * <table border="1">
 * <tr>
 * <th>Key</th>
 * <th>Description</th>
 * <th>Required?</th>
 * <th>Default</th>
 * </tr>
 * <tr>
 * <td>jndiName</td>
 * <td>JNDI name of the data source</td>
 * <td align="center">Yes</td>
 * <td align="center">n/a</td>
 * </tr>
 * </table>
 * 
 * @author KENNETHLCH
 * @version $Id: JNDIConnectionProvider.java,v 1.1.1.1 2013/08/16 05:35:48 tengyang Exp $
 */
public class JNDIConnectionProvider implements ConnectionProvider {
    
    private Logger logger;

    private String name;
    private String jndiName;
    private InitialContext ctx;

    @Override
    public void destroy() {
        logger.trace("destroy");
    }

    @Override
    public void init(Configuration config) throws SQLException, DataException {
        name = config.getString("name");
        jndiName = config.getString("jndiName");
        logger = Logger.getLogger(getClass().getName() + ":" + name);
        
        logger.trace("init");
        
        if (jndiName == null)
            throw new DataException(name + ": JNDI name is required");
        
        try {
            ctx = new InitialContext();
        } catch (NamingException e) {
            logger.error("", e);
            throw new DataException(e);
        }
    }

    @Override
    public void diagnose(PrintWriter out) {
        out.println("------------------------------------------------------------");
        out.println(this);
        out.println("------------------------------------------------------------");
        out.println("Container-managed data source information not available.");
    }

    @Override
    public String toString() {
        return super.toString() +
               String.format("[%s] jndiName=%s", name, jndiName);
    }

    @Override
    public Connection getConnection(final ConnectionFactory factory)
            throws SQLException {
        
        try {
            DataSource ds = (DataSource) ctx.lookup(jndiName);
            return new ConnectionWrapper(ds.getConnection()) {
                @Override
                public void close() throws SQLException {
                    super.close();
                    factory.setConnection(null);
                }
            };
        } catch (NamingException e) {
            logger.error("", e);
            throw new SQLException(e);
        }
    }

    @Override
    public String getName() {
        return name;
    }
}
